#第一步载入名人照片数据集
from sklearn.datasets import fetch_lfw_people						#导入名人人脸照片数据集
import matplotlib.pyplot as plt
data_home='C:\\Users\\43032\Desktop\\room\\ml-lesson\\03_dataset\\item7'
faces=fetch_lfw_people(min_faces_per_person=60)				             #选取最少有60张照片的数据作为训练集
x,y=faces.data,faces.target
target_names=faces.target_names
n_samples,h,w=faces.images.shape							#样本数量,图片的尺寸

#输出数据集信息
print(target_names)	             #显示名人的姓名
print(n_samples,h,w)	        #显示样本数量与照片尺寸



#第二步进行数据降维
from sklearn.decomposition import PCA					                                      #导入PCA降维算法

#降维处理，将数据集维度降低到150个
n_components=150
pca=PCA(n_components=n_components,svd_solver='randomized',
whiten=True,random_state=70).fit(x)
eigenfaces=pca.components_.reshape((n_components,h,w))				          #提取特征值
x_pca=pca.transform(x)	          #将训练集转化成低维度的特征向量

#以3行5列的形式显示降维后的照片
fig,ax=plt.subplots(3,5)
for i,axi in enumerate(ax.flat):
    axi.imshow(eigenfaces[i].reshape(h,w),cmap='bone')
    axi.set(xticks=[],yticks=[])
plt.show()



#第三步分割数据集、寻找最优值、输出评估报告
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV 
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
import numpy as np                       

#拆分数据集
x_train,x_test,y_train,y_test=train_test_split(x_pca,y,test_size=400,random_state=42)   

#网格搜索最优值
param_grid={'C':[1,5,10,50,100],'gamma':[0.0001,0.0005,0.001,0.005,0.01,0.1]}

grid=GridSearchCV(SVC(kernel="rbf",random_state=0),param_grid=param_grid,cv=5)
grid.fit(x_train,y_train)
print("最优参数值为：%s"%grid.best_params_)    

#获取最优模型
model=grid.best_estimator_		               
pred=model.predict(x_test)

#生成评估报告
re=classification_report(y_test,pred,target_names=faces.target_names)
print("最优模型的评估报告：")
print(re)



#第四步显示分类结果
fig,ax=plt.subplots(4,6)
for i,axi in enumerate(ax.flat):
   axi.imshow(eigenfaces[i].reshape(h,w),cmap='bone')					#绘制图像
   axi.set(xticks=[],yticks=[])
   box=dict(fc='black',alpha=0.4)	#设置边框样式
   axi.set_ylabel(faces.target_names[pred[i]].split()[-1],bbox=None if pred[i]==y_test[i] else box)	    #显示预测姓名，预测正确显示为黑色文字，预测错误显示为黑色加边框文字
plt.rcParams['font.sans-serif']='Simhei'
plt.suptitle('预测名人的姓名（加边框的名字表示预测错误）',size=10)
plt.show()


